package com.demo.java.concurrent.lock;

import com.clearspring.analytics.util.Lists;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import static com.demo.java.utils.DateUtils.currentDateTime;
import static com.demo.java.utils.ThreadUtils.threadName;

/**
 * 多次启动线程池, 保证一个任务只执行一次
 */
@Slf4j
public class LockCollectionTest {
    private static volatile Map<String, Lock> taskLockMap = new ConcurrentHashMap<>();
    private volatile Lock localLock = new ReentrantLock();
    public Lock tryLock(String lockKey) {
        if (taskLockMap.containsKey(lockKey)) {
            return taskLockMap.get(lockKey);
        }

        localLock.lock();
        try {
            if (taskLockMap.containsKey(lockKey)) {
                return taskLockMap.get(lockKey);
            }
            Lock lock = new ReentrantLock();
            taskLockMap.put(lockKey, lock);
            return lock;
        } finally {
            localLock.unlock();
        }

    }
    public void releaseLock(String lockKey) {
        taskLockMap.remove(lockKey);
    }
    static class MyThread implements Runnable {
        private String lockKey;
        private LockCollectionTest lockCollectionTest;
        public MyThread(String lockKey, LockCollectionTest lockCollectionTest) {
            this.lockKey = lockKey;
            this.lockCollectionTest = lockCollectionTest;
        }

        @Override
        public void run() {
            log.info("==== {}: {} enter", lockKey, threadName());
            Lock lock = lockCollectionTest.tryLock(lockKey);
            lock.lock();
            log.info("==== {}: {} get lock and sleep", lockKey, threadName());
            try {
                Thread.sleep(5000);
            } catch (InterruptedException ex) {
                log.error("error", ex);
            } finally {
                log.info("==== {}: {} release lock", lockKey, threadName());
                lock.unlock();
                lockCollectionTest.releaseLock(lockKey);
            }
        }
    }
    @Test
    public void lockCollectionTest() throws InterruptedException {
        String[] lockKey = {"transmit-rid-1", "transmit-rid-2", "transmit-rid-3"};
        List<Thread> threadList = Lists.newArrayList();
        for (int i = 0; i < 10; i++) {
            threadList.add(new Thread(new MyThread(lockKey[i % lockKey.length], this)));
        }

        for (Thread thread : threadList) {
            thread.start();
        }
        for (Thread thread : threadList) {
            thread.join();
        }
        Thread.sleep(1000);
        log.info("{}, {}", currentDateTime(), threadName());
    }
}
